using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace TrackSystem.IO.Utils
{
    /// <summary>
    /// 海康网络设备SDK类
    /// </summary>
    public class HCNetCamControl
    {
        private uint iLastErr = 0;
        private Int32 m_lUserID = -1;
        private HCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;
        private HCNetSDK.NET_DVR_FOCUSMODE_CFG focusMode;
        private HCNetSDK.NET_DVR_AEMODECFG exporeMode;
        private HCNetSDK.NET_DVR_SHOWSTRING_V30 strustStringInfo;
        private HCNetSDK.NET_DVR_PICCFG_V30 strustPICCFGInfo;
        public const int NET_DVR_GET_SHOWSTRING = 130;//获取叠加字符参数
        public const int NET_DVR_SET_SHOWSTRING = 131;//设置叠加字符参数
        //图象(NET_DVR_PICCFG_V30结构)
        public const int NET_DVR_GET_PICCFG_V30 = 1002;//获取图象参数
        public const int NET_DVR_SET_PICCFG_V30 = 1003;//设置图象参数
        private string str;
        private string ip, user, password;
        private int port;
        private int lChannel;

        // 字符叠加的变量
        private Boolean bFirst = true;
        private String head = "000.0";
        private String depth = "000.0";
        private String altitude = "00.0";
        private String deltaZ = "00.0";
        private String lon = "000.000000";
        private String lat = "00.000000";
        private String dive1 = "#";
        private String dive2 = "#";

        public HCNetCamControl(string ip, int port, string user, string password) {
            bool m_bInitSDK = HCNetSDK.NET_DVR_Init();
            if (m_bInitSDK == false)
            {
                Console.WriteLine("NET_DVR_Init error!");
                return;
            }
            this.ip = ip;
            this.port = port;
            this.user = user;
            this.password = password;
        }
        public void cbLoginCallBack(int lUserID, int dwResult, IntPtr lpDeviceInfo, IntPtr pUser)
        {
            string strLoginCallBack = "登录设备，lUserID：" + lUserID + "，dwResult：" + dwResult;

            if (dwResult == 0)
            {
                uint iErrCode = HCNetSDK.NET_DVR_GetLastError();
                strLoginCallBack = strLoginCallBack + "，错误号:" + iErrCode;
            }
        }
        public bool login() {
            try
            {
                //bool set_overtime = HCNetSDK.NET_DVR_SetRecvTimeOut(5000);
                bool set_overtime = HCNetSDK.NET_DVR_SetConnectTime(1000, 2);
                if (!set_overtime) {
                    Console.WriteLine("setTime fail");
                }

                DeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();

                //登录设备 Login the device
                m_lUserID = HCNetSDK.NET_DVR_Login_V30(ip, port, user, password, ref DeviceInfo);
                if (m_lUserID < 0)
                {
                    iLastErr = HCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_Login_V40 failed, error code= " + iLastErr; //登录失败，输出错误号
                    Console.WriteLine(str);
                    HCNetSDK.NET_DVR_Cleanup();
                    return false;
                }
                else
                {
                    //登录成功
                    lChannel = DeviceInfo.byChanNum;
                    Console.WriteLine(ip + ":Login Success!");
                    return true;
                }
            }
            catch (Exception ex)
            {

                return false;
                Console.WriteLine(ex.Message);
            }
        }
        public bool logout() {
            if (m_lUserID >= 0) {
                //注销登录 Logout the device                
                if (!HCNetSDK.NET_DVR_Logout(m_lUserID))
                {
                    iLastErr = HCNetSDK.NET_DVR_GetLastError();
                    str = "NET_DVR_Logout failed, error code= " + iLastErr;
                    Console.WriteLine(str);
                    return false;
                }
                m_lUserID = -1;

                return true;
            }
            return false;
        }

        ///# 云台控制 命令对应列表 command_id
        ///# ZOOM_IN 11 焦距变大(倍率变大)
        ///# ZOOM_OUT 12 焦距变小(倍率变小)
        ///# FOCUS_NEAR 13 焦点前调
        ///# FOCUS_FAR 14 焦点后调
        ///# IRIS_OPEN 15 光圈扩大
        ///# IRIS_CLOSE 16 光圈缩小
        ///# stop_id  0-开始动作  1-停止动作
        public bool setPTZPara(uint command_id, uint stop_id) {
            if (m_lUserID >= 0) {
                bool suss = HCNetSDK.NET_DVR_PTZControl_Other(m_lUserID, lChannel, command_id, stop_id);
                if (!suss) {
                    iLastErr = HCNetSDK.NET_DVR_GetLastError();
                    str = "云台PTZ设置失败, error code= " + iLastErr;
                    Console.WriteLine(str);
                    return false;
                }
                return true;
            }
            return false;
        }


        //获取聚焦参数
        public bool getFocusMode(out HCNetSDK.NET_DVR_FOCUSMODE_CFG focusModeConfig)
        {
            focusModeConfig = new HCNetSDK.NET_DVR_FOCUSMODE_CFG();
            UInt32 dwReturn = 0;
            Int32 dwOutBufferSize = Marshal.SizeOf(focusModeConfig);
            IntPtr lpOutBuffer = Marshal.AllocHGlobal(dwOutBufferSize);
            bool isGet = HCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, 3305, lChannel, lpOutBuffer, (UInt32)dwOutBufferSize, ref dwReturn);
            if (!isGet)
            {
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "获取聚焦参数失败, error code= " + iLastErr;
                Console.WriteLine(str);
                return false;
            }
            focusModeConfig = (HCNetSDK.NET_DVR_FOCUSMODE_CFG)Marshal.PtrToStructure(lpOutBuffer, typeof(HCNetSDK.NET_DVR_FOCUSMODE_CFG));
            Marshal.FreeHGlobal(lpOutBuffer);//释放指针
            return true;
        }

        //设置聚焦参数
        public bool setFocusMode(int focus_mode) {
            if (m_lUserID >= 0)
            {
                if (focusMode.dwSize == 0) {
                    focusMode = new HCNetSDK.NET_DVR_FOCUSMODE_CFG();
                    bool getConfig = getFocusMode(out focusMode);
                    if (!getConfig)
                    {
                        return false;
                    }
                }
                if (focusMode.byFocusMode != (byte)focus_mode)
                {
                    Int32 dwInBufferSize = Marshal.SizeOf(focusMode);
                    IntPtr lpInBuffer = Marshal.AllocHGlobal(dwInBufferSize);
                    focusMode.byFocusMode = (byte)focus_mode;
                    Marshal.StructureToPtr(focusMode, lpInBuffer, false);
                    bool success = HCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, 3306, lChannel, lpInBuffer, (UInt32)dwInBufferSize);
                    Marshal.FreeHGlobal(lpInBuffer);//释放指针
                    if (!success)
                    {
                        iLastErr = HCNetSDK.NET_DVR_GetLastError();
                        str = "对焦focus设置失败, error code= " + iLastErr;
                        Console.WriteLine(str);
                        return false;
                    }
                }
                return true;
            }
            return false;
        }

        // 获取曝光参数
        public bool getExporeMode(out HCNetSDK.NET_DVR_AEMODECFG exporeModeConfig) {
            exporeModeConfig = new HCNetSDK.NET_DVR_AEMODECFG();
            UInt32 dwReturn = 0;
            Int32 dwOutBufferSize = Marshal.SizeOf(exporeMode);
            IntPtr lpOutBuffer = Marshal.AllocHGlobal(dwOutBufferSize);
            bool isGet = HCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, 3309, lChannel, lpOutBuffer, (UInt32)dwOutBufferSize, ref dwReturn);
            if (!isGet)
            {
                Console.WriteLine("获取曝光参数失败");
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_GetDVRConfig, error code= " + iLastErr;
                Console.WriteLine(str);
                return false;
            }
            exporeModeConfig = (HCNetSDK.NET_DVR_AEMODECFG)Marshal.PtrToStructure(lpOutBuffer, typeof(HCNetSDK.NET_DVR_AEMODECFG));
            Marshal.FreeHGlobal(lpOutBuffer);//释放指针
            return true;
        }


        // 设置曝光参数
        public bool setExporeMode(int export_mode) {
            if (m_lUserID >= 0) {
                if (exporeMode.dwSize == 0) {
                    exporeMode = new HCNetSDK.NET_DVR_AEMODECFG();
                    bool getExpore = getExporeMode(out exporeMode);
                    if (!getExpore)
                    {
                        return false;
                    }
                }
                if (exporeMode.byExposureModeSet != (byte)export_mode)
                {
                    Int32 dwInBufferSize = Marshal.SizeOf(exporeMode);
                    IntPtr lpInBuffer = Marshal.AllocHGlobal(dwInBufferSize);
                    exporeMode.byExposureModeSet = (byte)export_mode;
                    Marshal.StructureToPtr(exporeMode, lpInBuffer, false);
                    bool success = HCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, 3310, lChannel, lpInBuffer, (UInt32)dwInBufferSize);
                    Marshal.FreeHGlobal(lpInBuffer);//释放指针
                    if (!success)
                    {
                        iLastErr = HCNetSDK.NET_DVR_GetLastError();
                        str = "iris设置失败, error code= " + iLastErr;
                        Console.WriteLine(str);
                        return false;
                    }
                }
                return true;
            }
            return false;
        }

        // 获取字符叠加
        public bool getShowStringInfo(out HCNetSDK.NET_DVR_SHOWSTRING_V30 strustStringInfo)
        {
            strustStringInfo = new HCNetSDK.NET_DVR_SHOWSTRING_V30();
            UInt32 dwReturn = 0;
            Int32 dwOutBufferSize = Marshal.SizeOf(strustStringInfo);
            IntPtr lpOutBuffer = Marshal.AllocHGlobal(dwOutBufferSize);
            bool isGet = HCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, NET_DVR_GET_SHOWSTRING, lChannel, lpOutBuffer, (UInt32)dwOutBufferSize, ref dwReturn);
            if (!isGet)
            {
                Console.WriteLine("获取OSD字符参数失败");
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_GetDVRConfig, error code= " + iLastErr;
                Console.WriteLine(str);
                return false;
            }
            strustStringInfo = (HCNetSDK.NET_DVR_SHOWSTRING_V30)Marshal.PtrToStructure(lpOutBuffer, typeof(HCNetSDK.NET_DVR_SHOWSTRING_V30));
            Marshal.FreeHGlobal(lpOutBuffer);//释放指针
            return true;
        }

        // 设置字符叠加 11-Heading 12-Depth 13-Altitude
        public bool setShowStringInfo(List<int> osd_index, List<double> value)
        {
            if (m_lUserID >= 0)
            {
                //int time1 = Environment.TickCount;
                if (strustStringInfo.struStringInfo == null) {
                    strustStringInfo = new HCNetSDK.NET_DVR_SHOWSTRING_V30();
                    bool getOSD = getShowStringInfo(out strustStringInfo);
                    if (!getOSD)
                    {
                        return false;
                    }
                }

                HCNetSDK.NET_DVR_SHOWSTRINGINFO setOSDString; //  time
                HCNetSDK.NET_DVR_SHOWSTRINGINFO setOSDString1; // heading-Depth-Altitue
                HCNetSDK.NET_DVR_SHOWSTRINGINFO setOSDString2; // Lon-Lat
                HCNetSDK.NET_DVR_SHOWSTRINGINFO setOSDString3; // Dive
                setOSDString = strustStringInfo.struStringInfo[0];
                setOSDString1 = strustStringInfo.struStringInfo[1];
                setOSDString2 = strustStringInfo.struStringInfo[2];
                setOSDString3 = strustStringInfo.struStringInfo[3];

                String time_Temp = "";
                String hda_Temp = "";
                String ll_Temp = "";
                String dive_Temp = "";

                for (var i = 0; i < osd_index.Count; i++) {
                    int osd_index_temp = osd_index[i] - 11;
                    if (osd_index_temp == 0)
                    {
                        head = Convert.ToString(Math.Round(value[i], 1)); // heading
                    }
                    else if (osd_index_temp == 1)
                    {
                        depth = Convert.ToString(Math.Round(value[i], 1));  // Depth
                    }
                    else if (osd_index_temp == 2)
                    {
                       altitude = Convert.ToString(Math.Round(value[i], 1)); // Altitude
                    }
                    else if (osd_index_temp == 3)
                    {
                       deltaZ = Convert.ToString(Math.Round(value[i], 1)); // deltaZ
                    }
                    else if (osd_index_temp == 4)
                    {
                        if (value[i] >= 0)
                        {
                            lon = Convert.ToString(value[i]) + "°E";   // lon
                        }
                        else
                        {
                            lon = Convert.ToString(value[i]) + "°W";   // lon
                        }
                    }
                    else if (osd_index_temp == 5)
                    {
                        if (value[i] >= 0)
                        {
                            lat = Convert.ToString(value[i])+"°N";   // lat
                        }
                        else {
                            lat = Convert.ToString(value[i])+ "°S";   // lat
                        }                      
                    }
                    else if (osd_index_temp == 6)
                    {
                        dive1 =  Convert.ToString(value[i]);   // 
                    }
                    else if (osd_index_temp == 7)
                    {
                        dive2 = Convert.ToString(value[i]);   // 
                    }
                }
                time_Temp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // time
                hda_Temp = "Head:" + head + "  " + "D:" + depth + "  " + "A:" + altitude + "   " + "Delta_Z:"+ deltaZ;
                ll_Temp = "Lon:" + lon + "  " + "Lat:" + lat;
                dive_Temp = "Dive:" + dive1 + "-" + dive2;

                setOSDString.sString = time_Temp;
                setOSDString1.sString = hda_Temp;
                setOSDString2.sString = ll_Temp;
                setOSDString3.sString = dive_Temp;

                setOSDString.wShowString = 1;
                setOSDString1.wShowString = 1;
                setOSDString2.wShowString = 1;
                setOSDString3.wShowString = 1;

                if (bFirst) {
                    setOSDString.wStringSize = Convert.ToUInt16(Marshal.SizeOf(setOSDString)); // 注释后可以右对齐
                    setOSDString1.wStringSize = Convert.ToUInt16(Marshal.SizeOf(setOSDString1)); // 注释后可以右对齐
                    setOSDString2.wStringSize = Convert.ToUInt16(Marshal.SizeOf(setOSDString2)); // 注释后可以右对齐
                    setOSDString3.wStringSize = Convert.ToUInt16(Marshal.SizeOf(setOSDString3)); // 注释后可以右对齐
                    bFirst = false;
                }

                //setOSDString.wShowStringTopLeftX = 608;
                //setOSDString.wShowStringTopLeftY = (ushort)(30 + osd_index_temp * 50);

                strustStringInfo.struStringInfo[0] = setOSDString;
                strustStringInfo.struStringInfo[1] = setOSDString1;
                strustStringInfo.struStringInfo[2] = setOSDString2;
                strustStringInfo.struStringInfo[3] = setOSDString3;

                //for (var i = 0; i < osd_index.Count; i++) {
                //    int osd_index_temp = osd_index[i] - 11;
                //    setOSDString = strustStringInfo.struStringInfo[osd_index_temp];
                //    if (osd_index_temp == 0){
                //        setOSDString.sString = "Head " + ":" + Convert.ToString(value[i]); // heading
                //    }else if (osd_index_temp == 1) {
                //        setOSDString.sString = "D " + ":" + Convert.ToString(value[i]);  // Depth
                //    } else if (osd_index_temp == 2) {
                //        setOSDString.sString = "A(m) " + ":" + Convert.ToString(value[i]); // Altitude
                //    } else if (osd_index_temp == 3) {
                //        setOSDString.sString = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // time
                //    } else if (osd_index_temp == 4) {
                //        setOSDString.sString = "Lon: "+Convert.ToString(value[i]);   // 
                //    }
                //    else if (osd_index_temp == 5)
                //    {
                //        setOSDString.sString = "Lat: " + Convert.ToString(value[i]);   // 
                //    }
                //    else if (osd_index_temp == 6)
                //    {
                //        setOSDString.sString = "Dive # " + Convert.ToString(value[i]);   // 
                //    }
                //    //setOSDString.wShowStringTopLeftX = 608;
                //    //setOSDString.wShowStringTopLeftY = (ushort)(30 + osd_index_temp * 50);
                //    setOSDString.wShowString = 1;
                //    setOSDString.wStringSize = Convert.ToUInt16(Marshal.SizeOf(setOSDString)); // 注释后可以右对齐
                //    strustStringInfo.struStringInfo[osd_index_temp] = setOSDString;
                //}
                Int32 dwInBufferSize = Marshal.SizeOf(strustStringInfo);
                IntPtr lpInBuffer = Marshal.AllocHGlobal(dwInBufferSize);
                Marshal.StructureToPtr(strustStringInfo, lpInBuffer, false);
                bool success = HCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, NET_DVR_SET_SHOWSTRING, lChannel, lpInBuffer, (UInt32)dwInBufferSize);
                Marshal.FreeHGlobal(lpInBuffer);//释放指针
                if (!success)
                {
                    iLastErr = HCNetSDK.NET_DVR_GetLastError();
                    str = "叠加OSD字符失败";
                    Console.WriteLine(str);
                    return false;
                }
                //int time2 = Environment.TickCount;
                //Console.WriteLine(time2 - time1);// (新网络相机的更新一次用的时间约为600ms,而老款为900ms)
                return true;
            }
            return false;
        }

        // OSD图像参数获取
        public bool getOSD(out HCNetSDK.NET_DVR_PICCFG_V30 strustPICCFGInfo)
        {
            strustPICCFGInfo = new HCNetSDK.NET_DVR_PICCFG_V30();
            UInt32 dwReturn = 0;
            Int32 dwOutBufferSize = Marshal.SizeOf(strustPICCFGInfo);
            IntPtr lpOutBuffer = Marshal.AllocHGlobal(dwOutBufferSize);
            bool isGet = HCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, NET_DVR_GET_PICCFG_V30, lChannel, lpOutBuffer, (UInt32)dwOutBufferSize, ref dwReturn);
            if (!isGet)
            {
                Console.WriteLine("获取OSD图像设置失败");
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_GetDVRConfig, error code= " + iLastErr;
                Console.WriteLine(str);
                return false;
            }
            strustPICCFGInfo = (HCNetSDK.NET_DVR_PICCFG_V30)Marshal.PtrToStructure(lpOutBuffer, typeof(HCNetSDK.NET_DVR_PICCFG_V30));
            Marshal.FreeHGlobal(lpOutBuffer);//释放指针
            return true;
        }
        public bool setOSD(int osd_index, double value)
        {
            if (m_lUserID >= 0)
            {
                strustPICCFGInfo = new HCNetSDK.NET_DVR_PICCFG_V30();
                bool getOSDPICCFG = getOSD(out strustPICCFGInfo);
                if (!getOSDPICCFG)
                {
                    return false;
                }
                if (osd_index == 19) {
                    strustPICCFGInfo.byFontSize = (System.Byte)value;
                } else if (osd_index == 20) {
                    strustPICCFGInfo.byAlignment = (System.Byte)value;
                } else if (osd_index == 21) {
                    strustPICCFGInfo.dwBoundary = (ushort)value;
                }
                else if (osd_index == 22)
                {
                    strustPICCFGInfo.byOSDColorType = (System.Byte)value;
                }
                else if (osd_index == 23)
                {
                    strustPICCFGInfo.struOsdColor.byRed = (System.Byte)value;
                }
                else if (osd_index == 24)
                {
                    strustPICCFGInfo.struOsdColor.byGreen = (System.Byte)value;
                }
                else if (osd_index == 25)
                {
                    strustPICCFGInfo.struOsdColor.byBlue = (System.Byte)value;
                }
                Int32 dwInBufferSize = Marshal.SizeOf(strustPICCFGInfo);
                IntPtr lpInBuffer = Marshal.AllocHGlobal(dwInBufferSize);
                Marshal.StructureToPtr(strustPICCFGInfo, lpInBuffer, false);
                bool success = HCNetSDK.NET_DVR_SetDVRConfig(m_lUserID, NET_DVR_SET_PICCFG_V30, lChannel, lpInBuffer, (UInt32)dwInBufferSize);
                Marshal.FreeHGlobal(lpInBuffer);//释放指针
                if (!success)
                {
                    iLastErr = HCNetSDK.NET_DVR_GetLastError();
                    str = "设置OSD图像失败";
                    Console.WriteLine(str);
                    return false;
                }
                return true;
            }
            return false;

        }
    }
}

